package co.fitstart.entity.utils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;

/**
 * 
 * @author downpour
 * @author lute
 */
public abstract class CollectionUtils {
	
    /**
     * Checks if string array is null or empty
     * 
     * @param array  the array to be checked
     * @return       {@code true} if the array is not null and all elements in the array
     *               are not null or empty or whitespace
     */
    public static boolean isArrayEmpty(String[] array) {
        boolean result = true;
        if (array != null) {
            for (int i = 0; i < array.length; i++) {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(array[i]))
                    return false;
            }
        }
        return result;
    }

    /**
     * Checks if string array has only one element
     * 
     * @param array  the array to be checked
     * @return       {@code true} if the array is not null and only has one element
     */
    public static boolean isArrayContainsSingleValue(String[] array) {
        if (array == null)
            return false;
        return array.length == 1;
    }

    /**
     * Extracts property of JavaBeans in the collection as a List
     * 
     * @param collection  the collection contains JavaBeans which property is extracted from
     * @param property    name of the property in the JavaBean
     * @return            a List comprised of property values extracted from JavaBeans in collection
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static List extractPropertyList(Collection collection, String property) {
        List result = new ArrayList();
        for (Iterator iter = collection.iterator(); iter.hasNext();) {
            try {
                result.add(PropertyUtils.getProperty(iter.next(), property));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
    
    /**
     * Constructs a Map transformed from a List of JavaBeans, whose key is the specified property's
     * value of JavaBean and value is the JavaBean itself. The order of entries in the Map is the 
     * same with the order of JavaBeans in the List.
     * 
     * @param collection  the List to be transformed contains JavaBeans which has
     *                    the property of specific name
     * @param property    name of property belongs to JavaBeans contained in List
     * @return            a Map whose key is the specific property's value and value is the
     *                    corresponding JavaBean in the List
     */
    public static <T> Map<String, T> constructMapValueFromList(List<T> collection, String property) {
        
        Map<String, T> result = new LinkedHashMap<String, T>();
        for (T bean : collection) {
            try {
                String key = PropertyUtils.getProperty(bean, property).toString();
                result.put(key, bean);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return result;
        
    }

    /**
     * Constructs a Map transformed from a List of JavaBeansm, whose key is the specific property's
     * value and its value is a list of JavaBeans with their own property's value is equal to the 
     * key, that is the specific property's value.
     * 
     * @param collection  the List to be transformed contains JavaBeans which has the property
     *                    whose name is specified by the property parameter
     * @param property    name of property which belongs to JavaBeans contained in the List
     * @return            a Map whose key is the specific property's value and value is a List of
     *                    JavaBeans whose own property's value is equal to the their Map entry's key
     */
    public static <T> Map<String, List<T>> constructMapValuesFromList(List<T> collection, String property) {
        
        Map<String, List<T>> result = new LinkedHashMap<String, List<T>>();
        
        for(T bean : collection) {
            try {
                String key = PropertyUtils.getProperty(bean, property).toString();
                if(!result.containsKey(key)) {
                    result.put(key, new ArrayList<T>());
                }
                result.get(key).add(bean);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } 
        }
        
        return result;
    }

}
